#ifndef __ATMOS_NetworkManager_h__
#define __ATMOS_NetworkManager_h__

#include "ATMOS_Common.h"
#include "ATMOS_PacketID.h"

#include <map>

namespace RakNet {

class RakPeerInterface;
class BitStream;
struct Packet;
struct RakNetStatistics;

} // end namespace RakNet

namespace ATMOS {

//--------------------------------------------------------------------------------------------------
//! mirrored from PacketPriority.h in RakNet -- see that file for details
//--------------------------------------------------------------------------------------------------
enum PacketReliability
{
	UNRELIABLE,
	UNRELIABLE_SEQUENCED,
	RELIABLE,
	RELIABLE_ORDERED,
	RELIABLE_SEQUENCED,
	UNRELIABLE_WITH_ACK_RECEIPT,
	UNRELIABLE_SEQUENCES_WITH_ACK_RECEIPT,
	RELIABLE_WITH_ACK_RECEIPT,
	RELIABLE_ORDERED_WITH_ACK_RECEIPT
};

enum PacketPriority
{
	IMMEDIATE_PRIORITY,
	HIGH_PRIORITY,
	MEDIUM_PRIORITY,   
	LOW_PRIORITY
};
//--------------------------------------------------------------------------------------------------


//! The base class for the two concrete NetworkManager types, NetworkManagerServer and NetworkManagerClient
/*! The NetworkManager interface wraps the RakNet::RakPeerInterface, and dispatches network events
	* to the registered PacketListener instances.
	* 
	* The NetworkManager is abstract and cannot be created directly.  Use the NetworkManagerClient
	* or NetworkManagerServer for this role.
*/
class AtmosExport NetworkManager
{
	NetworkManager( const NetworkManager &src );

public:
	typedef std::vector<PacketListener*> PacketListenerVector;
	// the RakNet packet ID for ATMOS packets
	static const RakNetPacketID sAtmosCustomPacketID;

public:
	NetworkManager();
	~NetworkManager();

	virtual	void initialize( const NetworkConnectionInfo &info ) = 0;
	virtual void shutdown();
	virtual void update();
				
	// RakNet packet handlers
	//----------------------------------------------------------------------------------------------
	virtual void onDisconnectionNotification( RakNet::Packet *packet );
	virtual void onAlreadyConnected( RakNet::Packet *packet );
	virtual void onIncompatibleProtocolVersion( RakNet::Packet *packet );
	virtual void onRemoteDisconnectionNotification( RakNet::Packet *packet );
	virtual void onRemoteConnectionLost( RakNet::Packet *packet );
	virtual void onNewIncomingConnection( RakNet::Packet *packet );
	virtual void onConnectionBanned( RakNet::Packet *packet );
	virtual void onConnectionAttemptFailed( RakNet::Packet *packet );
	virtual void onNoFreeIncomingConnections( RakNet::Packet *packet );
	virtual void onInvalidPassword( RakNet::Packet *packet );
	virtual void onConnectionLost( RakNet::Packet *packet );
	virtual void onConnectionRequestAccepted( RakNet::Packet *packet );
	virtual void onUnknownPacket( RakNet::Packet *packet );

	//! register a PacketListener instance, duplicates are not allowed
	void addPacketListener( PacketListener *listener );
	//! removed a PacketListener instance from the registration
	void removePacketListener( PacketListener *listener );
		
	//! send an ATMOS packet to the provided GUID
	void sendPacket( Packet *packet, const std::string &guid, 
		ATMOS::PacketPriority priority = ATMOS::HIGH_PRIORITY, 
		ATMOS::PacketReliability reliability = ATMOS::RELIABLE_ORDERED );
	//! broadcast an ATMOS packet to all connected peers
	void broadcastPacket( Packet *packet, ATMOS::PacketPriority priority = HIGH_PRIORITY,
		ATMOS::PacketReliability reliability = ATMOS::RELIABLE_ORDERED );
	void broadcastPacketToAllBut( Packet *packet, const std::string &nonRecipientGUID, 
		ATMOS::PacketPriority priority = ATMOS::HIGH_PRIORITY, 
		ATMOS::PacketReliability reliability = ATMOS::RELIABLE_ORDERED );

	//! get the local GUID
	std::string getLocalGUID() const;

	//! get the raw RakPeerInterface - using this directly will require you to use RakNet headers and lib
	RakNet::RakPeerInterface *getRakNetPeerInterface();

protected:
	void handleRakNetPacket( RakNet::Packet *packet );
	static RakNetPacketID getRakNetPacketID( RakNet::Packet *packet );

	virtual void onAtmosPacket( RakNet::Packet *packet );

protected:
	RakNet::RakPeerInterface *mPeerInterface;
	RakNet::RakNetStatistics *mStatistics;
	PacketListenerVector mPacketListeners;
	uint mShutdownTime;
};

} // end namespace ATMOS

#endif